package cn.jellybmedia.basic.service.impl;

import cn.jellybmedia.basic.constant.BaseConstants;
import cn.jellybmedia.basic.exception.BusinessException;
import cn.jellybmedia.basic.service.IVerifyCodeService;
import cn.jellybmedia.basic.utils.StrUtils;
import cn.jellybmedia.basic.utils.VerifyCodeUtils;
import cn.jellybmedia.basic.vo.RegisterVo;
import cn.jellybmedia.user.domain.User;
import cn.jellybmedia.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    // 注入邮件对象
    @Autowired
    private JavaMailSender javaMailSender;


    /**======================================================================================
    * @Title: getImage
    * @Description: 随机获取图片验证码
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/4 16:54
    * @Parameters: [imageCodeKey]
    * @Return java.lang.String
    ======================================================================================*/
    @Override
    public String getImage(String imageCodeKey) {
        // 判断传过来的值是否为空,为空抛出异常
        if (StringUtils.isEmpty(imageCodeKey)){
            throw new BusinessException("参数异常,请重新传入参数");
        }

        // 获取4位随机数
        String code = StrUtils.getComplexRandomString(4);

        // 把四位随机数用图片转换成图片
        String base64Str = VerifyCodeUtils.VerifyCode(100,40,code);

        // 存储到Redis中.
        redisTemplate.opsForValue().set(imageCodeKey,code,5, TimeUnit.MINUTES);


        return base64Str;
    }

    /**======================================================================================
    * @Title: getSmsCode
    * @Description: 发送手机验证码
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/6 18:32
    * @Parameters: [registerVo]
    * @Return void
    ======================================================================================*/
    @Override
    public void getSmsCode(RegisterVo registerVo) {
        // 获取参数
        String phone = registerVo.getPhone();

        // 获取业务类型
        String type = registerVo.getType();


        //1.非空校验
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)){
            throw new BusinessException("参数不能为空,请检查后重新输入!");
        }
        // 判断用户是注册还是微信登录的绑定
        if ("register".equals(type)){
            checkImageCode(registerVo);

            //3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.loadByPhone(phone);
            if (user != null){
                throw new BusinessException("手机已注册，请直接登录！");
            }
            sendCode(BaseConstants.RegisterCodeConstants.BUSINESS_REGISTER_PREFIX,phone);
        }else if ("binder".equals(type)){
            sendCode(BaseConstants.RegisterCodeConstants.BUSINESS_BINDER_PREFIX,phone);
        }


    }




    /**======================================================================================
    * @Title: checkImageCode
    * @Description: 图形验证码校验
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/10 18:09
    * @Parameters: [smsCodeDto]
    * @Return void
    ======================================================================================*/
    public void checkImageCode(RegisterVo registerVo) {
        // 图形验证码的key
        String imageCodeKey = registerVo.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = registerVo.getImageCodeValue();

        // 图形验证码判断
        if (StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue) ){
            throw new BusinessException("参数不能为空,请校验后输入");
        }
        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);

        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！");
        }
    }



    /**======================================================================================
    * @Title: sendCode
    * @Description: 发送手机验证码
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/10 18:13
    * @Parameters: [businessKey, phone]
    * @Return void
    ======================================================================================*/
    public void sendCode(String businessKey, String phone){
        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = businessKey + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);

        //0.定义一个空字符串，专门用来接收验证码
        String phoneCode = "";
        if (phoneCodeValue == null){//1.不存在
            //1.生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {//2.存在
            //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            Long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取！");
            }
            //2.将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendMessage(phone,"亲,您的验证码为" + smsCode + ",有效期为3分钟,请在3分钟内使用.");
        System.out.println("亲,您的验证码为" + phoneCode + ",有效期为3分钟,请在3分钟内使用.");
    }






















    /**======================================================================================
    * @Title: getEmailCode
    * @Description: 发送邮箱图片验证码
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/6 18:32
    * @Parameters: [registerVo]
    * @Return void
    ======================================================================================*/
    @Override
    public void getEmailCode(RegisterVo registerVo) {
        // 获取参数
        String email = registerVo.getEmail();
        // 图形验证码的key
        String imageCodeKey = registerVo.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = registerVo.getImageCodeValue();
        //后端
        //1.非空校验
        if (StringUtils.isEmpty(email)){
            throw new BusinessException("参数不能为空！");
        }
        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);

        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！");
        }

        //3.判断用户是否已注册，如果已注册提示用户
        User user = userMapper.loadByEmail(email);
        if (user != null){
            throw new BusinessException("邮箱已注册，请直接登录！");
        }

        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = BaseConstants.RegisterCodeConstants.BUSINESS_REGISTER_PREFIX + email;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);



        //0.定义一个空字符串，专门用来接收验证码
        String emailCode = "";
        if (phoneCodeValue == null){//1.不存在
            //1.生成新的随机验证码,并赋值给空字符串
            emailCode = StrUtils.getComplexRandomString(4);
        }else {//2.存在
            //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            Long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取！");
            }
            //2.将旧的验证码赋值给空字符串
            emailCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + emailCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送邮箱验证码
        // 1.创建复杂邮件对象
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        // 2.发送复杂邮件的工具类
        try {
            MimeMessageHelper helper = new MimeMessageHelper(mimeMessage,true,"utf-8");
            helper.setFrom("804854463@qq.com");
            helper.setSubject("宠物乐园验证码");
            // 3.设置文本内容，第二个参数 true 代表是否是一个html内容
            helper.setText("<h1>宠物乐园验证码</h1>"+
            "<h3>亲,您的验证码为"+emailCode+",有效时间为3分钟,请在3分钟内使用.</h3>",true);
            // 5.设置收件人
            helper.setTo(email);
            // 6.发送邮件
            javaMailSender.send(mimeMessage);
        }catch (RuntimeException e){
            e.printStackTrace();
        } catch (MessagingException e) {
            e.printStackTrace();
        }

    }



    /**======================================================================================
    * @Title: getSmsCode
    * @Description: 手机验证码登录
    * @Author: Mr.Zhang
    * @Version: 1.0
    * @Date:  2022/7/9 10:23
    * @Parameters: [registerVo]
    * @Return void
    ======================================================================================*/
    @Override
    public void phoneLoginSmsCode(RegisterVo registerVo) {
        // 获取参数
        String phone = registerVo.getPhone();
        // 图形验证码的key
        String imageCodeKey = registerVo.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = registerVo.getImageCodeValue();
        //后端
        //1.非空校验
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue)){
            throw new BusinessException("参数不能为空！");
        }

        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);

        if (imageCodeValueTmp == null){
            throw new BusinessException("验证码已过期，请重新获取！");
        }

        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)){
            throw new BusinessException("验证码错误，请重新输入！");
        }

        //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
        String phoneCodeKey = BaseConstants.RegisterCodeConstants.BUSINESS_REGISTER_PREFIX + phone;
        Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);

        //0.定义一个空字符串，专门用来接收验证码
        String phoneCode = "";
        if (phoneCodeValue == null){//1.不存在
            //1.生成新的随机验证码,并赋值给空字符串
            phoneCode = StrUtils.getComplexRandomString(4);
        }else {//2.存在
            //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
            String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
            // 之前存入code时，我们记录的时间戳
            Long oldTime = Long.valueOf(phoneCodeValueTmp[0]);
            // 现在的时间戳
            Long nowTime = System.currentTimeMillis();
            if (nowTime - oldTime < 1*60*1000){
                throw new BusinessException("请一分钟之后再获取！");
            }
            //2.将旧的验证码赋值给空字符串
            phoneCode = phoneCodeValueTmp[1];
        }
        //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
        String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
        redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
        //6.发送短信验证码
        // SmsUtils.sendMessage(phone,"亲,您的验证码为" + smsCode + ",有效期为3分钟,请在3分钟内使用.");
        System.out.println("亲,您的验证码为" + phoneCode + ",有效期为3分钟,请在3分钟内使用.");
    }





}
